#!/usr/bin/env python3
import random
import socket
import sys

from scapy.all import (
    IP,
    TCP,
    UDP,
    Ether,
    Packet,
    bind_layers,
    get_if_hwaddr,
    get_if_list,
    sendp
)
from scapy.fields import *


def get_if():
    ifs=get_if_list()
    iface=None # "h1-eth0"
    for i in get_if_list():
        if "eth0" in i:
            iface=i
            break;
    if not iface:
        print("Cannot find eth0 interface")
        exit(1)
    return iface

class SourceRoute(Packet):
   fields_desc = [ BitField("bos", 0, 1),
                   BitField("port", 0, 15)]

bind_layers(Ether, SourceRoute, type=0x1234)
bind_layers(SourceRoute, SourceRoute, bos=0)
bind_layers(SourceRoute, IP, bos=1)


def send_ip_packet(addr, iface, message):
    pkt = Ether(src=get_if_hwaddr(iface), dst='ff:ff:ff:ff:ff:ff')
    pkt = pkt / IP(dst=addr) / TCP(dport=1234, sport=random.randint(49152, 65535)) / message
    pkt.show2()
    sendp(pkt, iface=iface, verbose=False)

def send_source_route_packet(addr, iface, message):
    while True:
        s = input('Type space separated port nums (example: "2 3 2 2 1")  or  "q"  to quit : ')
        if s == "q":
            break

        try:
            port_list = list(map(int, s.strip().split()))
        except ValueError:
            print("Invalid input. Ports must be integers.")
            continue

        pkt = Ether(src=get_if_hwaddr(iface), dst='ff:ff:ff:ff:ff:ff', type=0x1234)
        for i, p in enumerate(port_list):
            bos = 1 if i == len(port_list) - 1 else 0
            pkt = pkt / SourceRoute(bos=bos, port=p)

        pkt = pkt / IP(dst=addr) / UDP(dport=4321, sport=1234) / message
        pkt.show2()
        sendp(pkt, iface=iface, verbose=False)


def main():

    # Usage guidance
    if len(sys.argv) < 3:
        print('ipv4 forwarding :   ./send.py <target IP address> <message>  --mode ip')
        print('source routing :   ./send.py <target IP address> <message>')
        exit(1)

    addr = socket.gethostbyname(sys.argv[1])
    message = sys.argv[2]
    mode = "sr"
    if len(sys.argv) > 3 and sys.argv[3] == "--mode" and len(sys.argv) > 4 and sys.argv[4] == "ip":
        mode = "ip"

    iface = get_if()
    print("sending on interface %s to %s" % (iface, str(addr)))

    if mode == "ip":
        send_ip_packet(addr, iface, message)
    else:
        send_source_route_packet(addr, iface, message)

if __name__ == '__main__':
    main()
